package console;

import java.io.*;

/**
 * User: sachinh
 * Date: 21-Dec-2008
 * Time: 20:54:09
 */
public class Console {
    private static boolean initSuccess = false;

    private static final String LIB_NAME = "consoleLib.dll";

    static {
        loadLibrary();

        initSuccess = nativeInit();
    }

    private static void loadLibrary() {
        // load the library by extracting it to a temporary directory - doesn't require PATH to be set
        File lib = new File(System.getProperty("java.io.tmpdir"), LIB_NAME);
        boolean exists = lib.exists();
        try {
            InputStream is = null;
            FileOutputStream fos = null;
            try {
                is = Console.class.getClassLoader().getResourceAsStream(LIB_NAME);
                if (is == null)
                    throw new IOException();
                fos = new FileOutputStream(lib);
                byte[] b = new byte[100*1024];
                for (int n = 0; n != -1; n = is.read(b)) {
                    fos.write(b, 0, n);
                }
            } finally {
                try {
                    if (is != null)
                        is.close();
                } catch (IOException e) {
                }
                try {
                    if (fos != null)
                        fos.close();
                } catch (IOException e) {
                }
            }
            System.load(lib.getAbsolutePath());
        } catch (Exception e) {
            if (exists) {
                System.load(lib.getAbsolutePath());
            } else {
                System.loadLibrary("consoleLib");
            }
            // JCurses library has a mechanism of locating the library relative to the location
            // from where this class was picked up - works assuming a directory structure for
            // the installation on disk. Not great for usage inside maven, etc
            // This is one area to explore to reduce the set up requirements of Console
        }
    }

    private native static boolean nativeInit();
    private native static int[] nativeReadChar();
    private native static void nativeOutputChars(String str);
    private native static int[] nativeGetCursorLocation();
    private native static boolean nativeSetCursorLocation(int x, int y);
    private native static int[] nativeGetScreenSize();

    public synchronized static Key readChar() {
        checkInit();
        int[] key = nativeReadChar();
        if (key.length == 0) {
            return null;
        }
        return new Key(key);
    }


    public synchronized static Key echoReadChar() {
        checkInit();
        Key key = readChar();
        if (key == null)
            return null;
        if (key.isCharacter()) {
            //outputChar(key.character);
            System.out.print(key.character);    // Use outputChar instead?
        }
        return key;
    }

    public synchronized static void outputChar(char c) {
        outputChars(new char[] { c }, 0, 1);
    }

    public synchronized static void outputChars(char[] str, int offset, int len) {
        outputChars(new String(str, offset, len));
    }

    public synchronized static void outputChars(char[] str) {
        outputChars(str, 0, str.length);
    }

    public synchronized static void outputChars(String str) {
        checkInit();
        nativeOutputChars(str);
    }

    public synchronized static Coord getCursorLocation() {
        checkInit();
        int[] pt = nativeGetCursorLocation();
        if (pt.length == 2)
            return new Coord(pt);
        return null;
    }

    public synchronized static boolean setCursorLocation(int x, int y) {
        checkInit();
        return nativeSetCursorLocation(x, y);
    }

    public synchronized static boolean setCursorLocation(Coord c) {
        checkInit();
        return setCursorLocation(c.x, c.y);
    }

    public synchronized static Rect getScreenSize() {
        checkInit();
        int[] pt = nativeGetScreenSize();
        if (pt.length == 4) {
            return new Rect(pt[0], pt[1], pt[2], pt[3]);
        }
        return null;
    }

    private static void checkInit() {
        if (!initSuccess)
            throw new IllegalStateException("Console Init failed");
    }
}
